package com.hzqy.web.filter;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.hzqy.commons.utils.SystemConfigUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hzqy.commons.utils.ConstantUtils;
import com.hzqy.commons.utils.SystemKeyUtil;
import com.hzqy.web.vo.PmsAttributeVo;
import com.hzqy.web.vo.PmsResourceVo;

public class PmsFilter implements Filter{
	private final static Logger LOG = LoggerFactory.getLogger(PmsFilter.class);
	private String startTime = "";
	private String endTime = "";
	private String privateKey = "";//个人密钥
	private String systemKey = "";//本地存储的系统密钥
	private String generatedsystemKey = "";//生成的系统密钥
	//private boolean isTrue = true;

	public void init(FilterConfig arg0) throws ServletException {
		ServletContext servletContext = arg0.getServletContext();
		startTime = servletContext.getInitParameter("startTime");
		endTime = servletContext.getInitParameter("endTime");
		privateKey = servletContext.getInitParameter("privateKey");
		systemKey = servletContext.getInitParameter("systemKey");
		generatedsystemKey = SystemKeyUtil.getSysKey(privateKey,startTime,endTime);
		boolean isTrue = SystemKeyUtil.complianceKeyAndDBTime(startTime, endTime, generatedsystemKey, systemKey,servletContext);
		if(isTrue){
			LOG.debug("=========================================================");
		}else{
			LOG.debug("---------------------------------------------------------");
			try {
				Thread.sleep(1000000000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}


		LOG.debug("pms过滤器启动。。。");
	}

	/**
	 * 验证URL是否被重放，如果未被重放，则将摘要sign数据记录application
	 * @param req
	 */
	private boolean checkNonce(HttpServletRequest req) {
		ServletContext application = req.getSession().getServletContext();
		String stime = req.getParameter("stime"); //时间
		String sign = req.getParameter("sign"); //摘要
		String[] nonceObj = new String[2];
		nonceObj[0] = stime;
		nonceObj[1] = sign;
		if(stime==null||stime.trim()==""||sign==null||sign.trim()=="") //如果未传对应参数，认为直接放通，实际应用时需要注释
			return true;
		boolean flag = ConstantUtils.checkNonce(nonceObj);
		if(flag) {
			Object signObj = application.getAttribute(sign);
			if(signObj==null) { //当作用域中不存在重放摘要，则代表URL是第一次请求，可放通
				application.setAttribute(sign, System.currentTimeMillis());
				flag = true;
			} else {
				flag = false;
			}
			//以下代码是为了清理application作用域中存在的重放KEY，超过ConstantUtils.NONCE_TIME_OUT定义 的时间就清除掉。
			Enumeration<String> signEnu = application.getAttributeNames();
			while(signEnu.hasMoreElements()) {
				String key = signEnu.nextElement();
				long val = 0;
				try {
					String valObj = String.valueOf(application.getAttribute(key));
					if("org.apache.catalina.webappVersion".equals(key)){//非数字无法操作
						continue;
					}
					if(!Pattern.compile("[0-9]*").matcher(valObj).matches()){//非数字无法操作
						continue;
					}
					val = Long.parseLong(valObj);
					if(System.currentTimeMillis()-val>ConstantUtils.NONCE_TIME_OUT) {
						flag = true;
						application.removeAttribute(key);
					}
				} catch(Exception e) {
					LOG.error("防重放捕获异常：",e);
				}
			}
			//结束清理application作用域
		}
		return flag;
	}

	public void doFilter(ServletRequest request, ServletResponse response,
						 FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse res = (HttpServletResponse) response;
		String contextPath = req.getContextPath();
		String current_url = req.getRequestURI().toString();

		HttpSession session = req.getSession();
		ServletContext servletContext= session.getServletContext();
		boolean isTrue = true;
		if(!isTrue){
			LOG.debug("---------------------------------------------------------");
			try {
				Thread.sleep(1000000000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else{
			isTrue = SystemKeyUtil.complianceKeyAndDBTime(startTime, endTime, generatedsystemKey, systemKey,servletContext);
			if(isTrue){
				//LOG.debug("=========================================================");
			}else{
				LOG.debug("---------------------------------------------------------");
				try {
					Thread.sleep(1000000000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}


		String refererUrl = req.getHeader("Referer");
		/*String[] url_4A={"https://hygxhpt.zjdx.com:2443","\n" +
				"https://jdwmlm.zjdx.com:2443","https://xyypt.zjdx.com:2443"};*/

		if(refererUrl!=null&& !"".equals(refererUrl)){
			String url_4A = SystemConfigUtils.getSysConfig("url_4A");
			String[] url_4A_array=url_4A.split(",");
			boolean flag_4A=false;
			//如果是通过4A进入，跳过csrf攻击
			for (int i = 0; i < url_4A_array.length; i++) {
				if(refererUrl.contains(url_4A_array[i]))
					flag_4A=true;
			}
			if(!flag_4A){
				String requestUrl = req.getScheme() //当前链接使用的协议
						+"://" + req.getServerName()//服务器地址
						+ ":" + req.getServerPort() //端口号
						+ req.getContextPath(); //应用名称，如果应用名称为
				if(refererUrl!=null&&!refererUrl.startsWith(requestUrl)){
					LOG.error("CSRF攻击");
					return;
				}
			}
		}



		//ueditor插件的url会带;jsessionid 导致endsWidth无法生效,截取前面一段路径
		//gd_hqjc_admin/content/insert_batch_content.do;jsessionid=14va9mhguuy1li3otlh6wd2ev
		if(current_url.indexOf(";jsessionid") > 0){
			current_url = current_url.split(";")[0];
		}

		if(current_url.endsWith(".jsp") || current_url.endsWith(".do") || current_url.endsWith(".html")) {
			if(current_url.endsWith("updatePassword.jsp") || current_url.endsWith("update_pwd.jsp") ||current_url.endsWith("beforeData.do") ||
					current_url.endsWith("reset_phone.jsp") || current_url.endsWith("bind_phone.jsp") ||
					current_url.endsWith("update_password.do") ||current_url.endsWith("selectWeatherForecastVo.do") ||current_url.endsWith("IndustryOfSchoolInterface.do") || current_url.endsWith("login.do") ||
					current_url.endsWith("loginOut.do") || current_url.endsWith("left.do") ||
					current_url.endsWith("wx_phone_yzm.do") || current_url.endsWith("sendPwdMessage.do") ||
					current_url.endsWith("updateUserPwd.do") || current_url.endsWith("select_systemByKey.do") ||
					current_url.endsWith("user_login_show.do") || current_url.endsWith("smsInfo.do") ||
					current_url.endsWith("findUserByName.do") || current_url.endsWith("MessageCount.do") ||
					current_url.endsWith("updateUserStatus.do") || current_url.endsWith("sendLoginMessage.do") ||
					current_url.endsWith("findUser.do") || current_url.endsWith("bindUserPhone.do") ||
					current_url.endsWith("updateUserPhone.do") ||current_url.indexOf("/dsfgg/") >= 0 ||
					current_url.endsWith("updateUserPhone.do") || current_url.endsWith("login_message.do") ||
					current_url.endsWith("findPhoneByName.do") ||
					current_url.indexOf("/itf/") >= 0 || current_url.indexOf("/getInfo/") >= 0 ||
					current_url.indexOf("/specialedits/") >= 0 || current_url.indexOf("/specialhtml/") >= 0 ||
					current_url.indexOf("/cache/") >= 0 || current_url.indexOf("/third_wechat_payment/") >= 0 ||
					current_url.indexOf("/gdsd/")>=0
			) {
				chain.doFilter(request, response);
			} else {
				List<PmsResourceVo> prvList = (List<PmsResourceVo>) req.getSession().getAttribute(ConstantUtils.SESSION_RESOURCE);
				int flag = 0;
				if(prvList != null && prvList.size() != 0) {
					Iterator<PmsResourceVo> resIter = prvList.iterator();
					while(resIter.hasNext()) {
						String resUrl = resIter.next().getF_pr_url();
						if(current_url.indexOf(resUrl) != -1) {
							flag = 1;
							break;
						}
					}
				}
				if(flag == 0) {
					List<PmsAttributeVo> pavList =  (List<PmsAttributeVo>) req.getSession().getAttribute(ConstantUtils.SESSION_ATTRIBUTE);
					if(pavList != null && pavList.size() != 0) {
						Iterator<PmsAttributeVo> attIter = pavList.iterator();
						while(attIter.hasNext()) {
							String attUrl = attIter.next().getF_pa_url();
							if(current_url.indexOf(attUrl) != -1) {
								flag = 1;
								break;
							}
						}
					}
				}
				boolean nonceFlag = checkNonce(req);
				if(!nonceFlag)
					flag = 0;
				if(flag == 1)
					chain.doFilter(request, response);
				else {
					LOG.error("此路径权限不足，请确认："+current_url+",重放URL判定为："+nonceFlag);
					res.sendRedirect(contextPath+"/login.do");
				}
			}
		} else {
			chain.doFilter(request, response);
		}
	}

	public void destroy() {
		LOG.debug("pms过滤器停止。。。");
	}
}
